package checkClass;

import baseClass.ErrorSema;
import baseClass.SemaErrorEnum;
import errorHandle.ErrorDeliver;
import symbolClass.FunctionNode;
import symbolClass.ParaMap;

import java.util.LinkedList;

/*
    类型检查总封装类
    2022-3-11-杨海南
 */
public class TypeCheck {
    //para图
    private ParaMap paraMap = ParaMap.getParaMapInstance();
    private ErrorDeliver errorDeliver = ErrorDeliver.getErrorDeliverInstance();
    private static TypeCheck typeCheck = new TypeCheck();
    private TypeCheck(){}
    public static TypeCheck getTypeCheckInstance(){return typeCheck;}

    public boolean checkTypeEqual(TypeExpression typeExpression1,TypeExpression typeExpression2){
        return typeExpression1.typeEquals(typeExpression2.getTypeNode());
    }
    public TypeExpression checkOpType(TypeExpression innerType, TypeExpression outerType) {
        if (innerType.typeEquals(BaseTypeEnum.INTEGER) && outerType.typeEquals(BaseTypeEnum.INTEGER)) {
            return new TypeExpression(BaseTypeEnum.INTEGER);
        } else if (innerType.typeEquals(BaseTypeEnum.REAL) && outerType.typeEquals(BaseTypeEnum.INTEGER)) {
            return new TypeExpression(BaseTypeEnum.REAL);
        } else if (innerType.typeEquals(BaseTypeEnum.INTEGER) && outerType.typeEquals(BaseTypeEnum.REAL)) {
            return new TypeExpression(BaseTypeEnum.REAL);
        } else if (innerType.typeEquals(BaseTypeEnum.REAL) && outerType.typeEquals(BaseTypeEnum.REAL)) {
            return new TypeExpression(BaseTypeEnum.REAL);
        } else {
            return new TypeExpression(ToolTypeEnum.ERROR);
        }
    }
    public TypeExpression funcTypeCheck(String funcName, LinkedList<TypeExpression> realTypeList,int line,int inLine){
        TypeExpression resultType=null;
        if (paraMap.containsFunction(funcName)) {
            //函数声明的类型
            TypeExpression[] funcExpressionList;
            FunctionNode func = paraMap.getFunction(funcName);
            int paraNum = func.getParaNum();
            funcExpressionList = func.getParaTypeList();

            //实际传入的参数
            int paraNumReal = realTypeList.size();
            if (paraNumReal != paraNum) {
                // 添加到错误流，参数个数不匹配
                String tips="函数:'"+funcName+"'调用参数个数不匹配，请检查调用语句";
                ErrorSema errorSema = new ErrorSema(line,inLine, SemaErrorEnum.MISMATCH,tips);
                errorDeliver.addNewSemaError(errorSema);
                resultType=new TypeExpression(ToolTypeEnum.ERROR);
            } else {
                int index=0;
                for (; index < paraNum; index++) {
                    TypeNode definedType = ((TypeConstructor)funcExpressionList[index].getTypeNode()).getSonList().get(1);
                    //如果参数类型不匹配
                    if (!realTypeList.get(index).typeEquals(definedType)) {
                        // 添加到错误流，类型不匹配
                        String tips="函数:'"+funcName+"'调用参数类型不匹配，请检查调用语句";
                        ErrorSema errorSema = new ErrorSema(line,inLine, SemaErrorEnum.MISMATCH,tips);
                        errorDeliver.addNewSemaError(errorSema);
                        resultType=new TypeExpression(ToolTypeEnum.ERROR);

                        //退出循环
                        break;
                    }
                }
                //表示全部匹配
                if(index==paraNum){
                    resultType=new TypeExpression(func.getReturnType());
                }
            }
        } else {
            //  错误流，没声明这个函数
            String tips="函数:'"+funcName+"'未声明";
            ErrorSema errorSema = new ErrorSema(line,inLine, SemaErrorEnum.UNDEFINE,tips);
            errorDeliver.addNewSemaError(errorSema);
            resultType=new TypeExpression(ToolTypeEnum.ERROR);
        }
        return resultType;
    }
}
